from typing import Generic, TypeVar, Type, Optional, List, Any, Dict
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update, delete, func
from sqlalchemy.orm import selectinload

from app.models.base import BaseModel

ModelType = TypeVar("ModelType", bound=BaseModel)


class BaseService(Generic[ModelType]):
    """基础服务类"""

    def __init__(self, model: Type[ModelType]):
        self.model = model

    async def get_by_id(
        self, db: AsyncSession, *, id: int, tenant_id: Optional[str] = None
    ) -> Optional[ModelType]:
        """根据ID获取记录"""
        query = select(self.model).where(
            self.model.id == id, self.model.is_deleted == False
        )

        # 如果是多租户模型，添加租户过滤
        if hasattr(self.model, "tenant_id") and tenant_id:
            query = query.where(self.model.tenant_id == tenant_id)

        result = await db.execute(query)
        return result.scalar_one_or_none()

    async def get_multi(
        self,
        db: AsyncSession,
        *,
        skip: int = 0,
        limit: int = 20,
        tenant_id: Optional[str] = None,
        filters: Optional[Dict[str, Any]] = None,
        order_by: Optional[str] = None,
    ) -> List[ModelType]:
        """分页获取记录列表"""
        query = select(self.model).where(self.model.is_deleted == False)

        # 租户过滤
        if hasattr(self.model, "tenant_id") and tenant_id:
            query = query.where(self.model.tenant_id == tenant_id)

        # 动态过滤条件
        if filters:
            for field, value in filters.items():
                if hasattr(self.model, field) and value is not None:
                    query = query.where(getattr(self.model, field) == value)

        # 排序
        if order_by:
            if order_by.startswith("-"):
                field = order_by[1:]
                if hasattr(self.model, field):
                    query = query.order_by(getattr(self.model, field).desc())
            else:
                if hasattr(self.model, order_by):
                    query = query.order_by(getattr(self.model, order_by))
        else:
            query = query.order_by(self.model.id.desc())

        # 分页
        query = query.offset(skip).limit(limit)

        result = await db.execute(query)
        return result.scalars().all()

    async def get_count(
        self,
        db: AsyncSession,
        *,
        tenant_id: Optional[str] = None,
        filters: Optional[Dict[str, Any]] = None,
    ) -> int:
        """获取记录总数"""
        query = select(func.count(self.model.id)).where(self.model.is_deleted == False)

        # 租户过滤
        if hasattr(self.model, "tenant_id") and tenant_id:
            query = query.where(self.model.tenant_id == tenant_id)

        # 动态过滤条件
        if filters:
            for field, value in filters.items():
                if hasattr(self.model, field) and value is not None:
                    query = query.where(getattr(self.model, field) == value)

        result = await db.execute(query)
        return result.scalar()

    async def create(
        self, db: AsyncSession, *, obj_in: Dict[str, Any], tenant_id: Optional[str] = None
    ) -> ModelType:
        """创建记录"""
        db_obj_data = dict(obj_in)

        # 如果是多租户模型，设置租户ID
        if hasattr(self.model, "tenant_id") and tenant_id:
            db_obj_data["tenant_id"] = tenant_id

        db_obj = self.model(**db_obj_data)
        db.add(db_obj)
        await db.commit()
        await db.refresh(db_obj)
        return db_obj

    async def update(
        self,
        db: AsyncSession,
        *,
        db_obj: ModelType,
        obj_in: Dict[str, Any],
    ) -> ModelType:
        """更新记录"""
        obj_data = dict(obj_in)

        # 移除None值
        obj_data = {k: v for k, v in obj_data.items() if v is not None}

        for field, value in obj_data.items():
            if hasattr(db_obj, field):
                setattr(db_obj, field, value)

        db.add(db_obj)
        await db.commit()
        await db.refresh(db_obj)
        return db_obj

    async def remove(
        self, db: AsyncSession, *, id: int, tenant_id: Optional[str] = None
    ) -> Optional[ModelType]:
        """软删除记录"""
        db_obj = await self.get_by_id(db, id=id, tenant_id=tenant_id)
        if db_obj:
            db_obj.is_deleted = True
            db.add(db_obj)
            await db.commit()
            await db.refresh(db_obj)
        return db_obj

    async def hard_delete(
        self, db: AsyncSession, *, id: int, tenant_id: Optional[str] = None
    ) -> Optional[ModelType]:
        """硬删除记录"""
        db_obj = await self.get_by_id(db, id=id, tenant_id=tenant_id)
        if db_obj:
            await db.delete(db_obj)
            await db.commit()
        return db_obj